// This file is a part of Funky C++.
// Copyright (C) 2011  Valentin David
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
#ifndef PORT_HH
# define PORT_HH

# include <jack/jack.h>
# include <memory>

namespace jack {
  struct client;

  struct port_handler {
  public:
    client* cl_ptr;
    ::jack_port_t* handle;

    port_handler(client* cl_ptr,
		 ::jack_port_t* handle)
      : cl_ptr(cl_ptr),
	handle(handle) {}

    ~port_handler();
  };

  template <typename Sample = ::jack_default_audio_sample_t>
  struct port {
  private:
    friend struct client;
    std::shared_ptr<port_handler> handle;
    std::function<void(::jack_nframes_t,
		       Sample*)>
    cb;

    void callback(::jack_nframes_t nframes) {
      Sample *buffer =
	(Sample*)::jack_port_get_buffer(handle->handle, nframes);
      cb(nframes, buffer);
    }

  public:
    port(const port& other);

    port(port&& other);

    port& operator=(const port&) = delete;
    port& operator=(port&& other) {
      std::swap(handle, other.handle);
      return *this;
    }

    port(client* cl_ptr,
	 ::jack_port_t* handle):
      handle(new port_handler(cl_ptr, handle)),
      cb([](::jack_nframes_t,
	    Sample*){}) {}

    template <typename T>
    void set_callback(T&& t) {
      std::function<void(::jack_nframes_t,
			 Sample*)> n(std::forward<T>(t));
      std::swap(cb, n);
    }

    ~port();

    bool operator==(const port& other) const {
      return this->handle == other.handle;
    }
  };

}

#endif
